package com.longge.websocket.endpoint;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import com.longge.websocket.timer.SseTimer;

import lombok.extern.slf4j.Slf4j;

/**
 * SSE的SpringBoot 3种实现方案
 * 
 * @author roger yang
 *
 */
@RestController
@RequestMapping("/sse")
@Slf4j
public class SseRest {
	@Autowired
	private SseTimer sseTimer;

	/**
	 * 存在的问题： 客户端直接关闭浏览器/调用EventSource的close方法，这边无法检测到并终止send，原因未知
	 * 注意点：消息必须data:开头，\n\n结束
	 * @param resp
	 */
	@GetMapping(value = "/push")
	public void index(HttpServletResponse resp) {
		boolean flag = true;
		try {
			resp.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);
			resp.setCharacterEncoding("utf-8");
			while (flag) {
				Thread.sleep(RandomUtils.nextLong(100L, 5000L));
				
				String data = String.valueOf(RandomUtils.nextInt(0, Integer.MAX_VALUE));

				String msg = "data:" + data + "\n\n";
				resp.getWriter().write(msg);
				resp.getWriter().flush();
				
				log.info("push data:{}", data);
			}
		} catch (Exception e) {
			log.error("sse error", e);
			flag = false;
			try {
				resp.getWriter().close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
	
	/**
	 * 推荐使用
	 * @param resp
	 * @return
	 * @throws IOException
	 */
	@GetMapping(value = "/push2", produces = { MediaType.TEXT_EVENT_STREAM_VALUE })
	public SseEmitter push2(HttpServletResponse resp) throws IOException {
		/**
		 * 这里设置构造函数的timeout为0，表示永不超时。
		 * 如果不设置则会在默认时间（30秒）后超时并关闭连接
		 */
		SseEmitter emitter = new SseEmitter(0L);
		sseTimer.addClient(emitter);
		return emitter;
	}

	/**
	 * NOT GOOD WORK!!!!
	 * 因为一旦return了，SpringMVC的servlet就会把连接关闭掉，也就是只会返回一次数据给前台
	 * 如果想要使用这种方式，最好的是使用WebFlux
	 * 注意点：消息必须data:开头，\n\n结束
	 * @param resp
	 * @return
	 */
	@GetMapping(value = "/push3", produces = { MediaType.TEXT_EVENT_STREAM_VALUE })
	@Deprecated
	public String push3(HttpServletResponse resp) {
		String data = String.valueOf(RandomUtils.nextInt(0, Integer.MAX_VALUE));
		String msg = "data:" + data + "\n\n";
		log.info("push data:{}", msg);
		return msg;
	}
}
